package ign.behaviours.building;

import ign.Performatives;
import ign.ProgramParams;
import ign.agents.Building;
import jade.core.AID;
import jade.core.behaviours.Behaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import java.awt.Rectangle;
import java.util.Random;

/**
 * Classe s'occupant de résoudre un conflit entre deux agents.
 * En premier lieu ils s'envoient leurs informations pour décider de
 * qui se déplace et vers ou.
 * @author Simon Bourigaut & Ghislain Di Paolo
 */
public class Move extends Behaviour {
	
	private static final long serialVersionUID = -1970363435203845199L;
	public static final int TIMEOUT = 1000000;
	
	private AID aid ;
	private boolean answerReceived ;
	private boolean messageSent ;
	private boolean done ;
	private ACLMessage msg ;
	private int maxReceive = TIMEOUT ;
	
	/**
	 * Constructeur prenant l'agent avec qui celui qui execute se Behaviour est en conflit.
	 * @param aid Le numéro de l'autre agent.
	 */
	public Move(AID aid) {
		
		this.aid = aid ;
		this.answerReceived = false ;
		this.messageSent = false ;
		this.done = false ;
		this.msg = null ;
	}
	
	@Override
	public void action() {
		
		Building me = (Building) myAgent;
		int x = me.getX();
		int y = me.getY();
		int width = me.getWidth();
		int height = me.getHeight();
		int my_state = me.getPropState();
		int orig_x = me.getOrigX();
		int orig_y = me.getOrigY();
				
		int his_x = 0;
		int his_y = 0;
		int his_width = 0;
		int his_height = 0;
		int his_state = 0;
		int his_orig_x = 0;
		int his_orig_y = 0;

		int his_aera = 0;
		int my_aera = 0;

		Rectangle my_rect = null;
		Rectangle his_rect = null;
		Rectangle intersection = null;
		
		/* Envoie ses propres informations */
		if(!messageSent) {
			ACLMessage mess = new ACLMessage(Performatives.AGENT_INFO);			
			mess.setContent("" + x + ";" + y + ";" + width + ";" + height + ";" + me.getPropState() + ";" + orig_x + ";" + orig_y);
			mess.addReceiver(aid) ;
			myAgent.send(mess) ;
			messageSent = true ;
			return ;
		}
		
		/* Vérifie que la réponse est arrivé */
		else if(!answerReceived) {
			
			MessageTemplate pattern = MessageTemplate.and(
				MessageTemplate.MatchPerformative(Performatives.AGENT_INFO),
				MessageTemplate.MatchSender(aid)) ;
			msg = myAgent.receive(pattern) ;
			
			if (msg != null){
				answerReceived = true ;
				maxReceive = TIMEOUT;
								
				String content = msg.getContent();
				String[] params = content.split(";");
				
				his_x = Integer.parseInt(params[0]);
				his_y = Integer.parseInt(params[1]);
				his_width = Integer.parseInt(params[2]);
				his_height = Integer.parseInt(params[3]);
				his_state = Integer.parseInt(params[4]);
				his_orig_x = Integer.parseInt(params[5]);
				his_orig_y = Integer.parseInt(params[6]);
				
				his_aera = his_width * his_height;
				my_aera = width * height;
				
				my_rect = new Rectangle(x, y, width, height);
				his_rect = new Rectangle(his_x, his_y, his_width, his_height);
				intersection = my_rect.intersection(his_rect);
				
				if (intersection.isEmpty()){
					
					done = true;
					return;
				}
			}
			else
				return ;
			
			/* Timeout */
			if (--maxReceive == 0)
				done = true ;
		}
		
		/* Quand les informations sont connues le protocole s'execute */
		if(answerReceived) {
			if (msg.getPerformative() == Performatives.AGENT_INFO) {
				
				/* Cette partie s'occupe de la propagation */				
				boolean haveToMove = true;
				
				switch (ProgramParams.move_priority) {
				case YOUNGER :
					haveToMove = (me.getAID().compareTo(aid) > 0);
					break;
				case OLDER :
					haveToMove = (me.getAID().compareTo(aid) < 0);
					break;
				case LITTLE_STATE :
					haveToMove = (my_state <= his_state) ? true : false;
					break;
				case BIG_STATE :
					haveToMove = (my_state >= his_state) ? true : false;
					break;
				case CLOSER_ORIGINAL :
					int my_dist = Math.abs(x - orig_x) + Math.abs(y - orig_y);
					int his_dist = Math.abs(his_x - his_orig_x) + Math.abs(his_y - his_orig_y);
					haveToMove = (my_dist >= his_dist) ? true : false;
					break;
				case FURTHER_ORIGINAL :
					int my_dist2 = Math.abs(x - orig_x) + Math.abs(y - orig_y);
					int his_dist2 = Math.abs(his_x - his_orig_x) + Math.abs(his_y - his_orig_y);
					haveToMove = (my_dist2 >= his_dist2) ? true : false;
					break;
				case SMALLER_AREA :
					haveToMove = (my_aera <= his_aera) ? true : false;
					break;
				case BIGGER_AREA:
					haveToMove = (my_aera >= his_aera) ? true : false;
					break;
				}
				
				int bigger_state = Math.max(my_state, his_state);
				
				if (haveToMove){	
					if (bigger_state >= ProgramParams.max_propagate)
						me.doDelete();
					else
						do_move(me, intersection, x, y, his_x, his_y);

					me.setPropState(bigger_state + 1);

					done = true;
				}
				
				done = true;
			}
		}
	}
	
	/* Déplace le building dans une direction au hasard */
	private void do_move(Building me, Rectangle intersection, int x, int y, int his_x, int his_y){
		
		Random r = new Random() ;
		int r1 = r.nextInt(2);
		int r2 = r.nextInt(2);
		float coef = ProgramParams.move_coef;

		if (r1 == 0 && r2 == 0)
			r1 = 1 ;

		float do_r1 = intersection.width * r1 * coef;
		float do_r2 = intersection.height * r2 * coef;
		int int_r1 = (int) do_r1;
		int int_r2 = (int) do_r2;

		if (int_r1 == 0)
			int_r1 = 2;
		if (int_r2 == 0)
			int_r2 = 2;

		if (his_x >= x && his_y >= y)
			me.move(-int_r1, -int_r2);

		else if (his_x >= x && his_y <= y)
			me.move(-int_r1, int_r2);

		else if (his_x <= x && his_y >= y)
			me.move(int_r1, -int_r2);

		else if (his_x <= x && his_y <= y)
			me.move(int_r1, int_r2);
	}

	@Override
	public boolean done() {
		
		return done;
	}

}
